using System;
using System.IO;
using System.Collections.Generic;

namespace SoftwareMonkeys.FileNodes
{
	/// <summary>
	/// 
	/// </summary>
	public class FileNodeScanner
	{
		public FileNode RootNode;

		public IOutputListener Listener = new ConsoleListener();

		public FileNodeLoader Loader { get;set; }
				
		public FileNodeScanner(
			FileNodeLoader loader,
			IOutputListener listener
		)
		{
			Loader = loader;
			Listener = listener;
		}
		
		public bool IsExcludedFromTarget(string propertiesFile)
		{
			// Exclude anything within the imports folder
			return propertiesFile.IndexOf(Path.DirectorySeparatorChar + "Imports" + Path.DirectorySeparatorChar) > -1;
		}

		public FileNode ScanDirectory(string targetDirectory)
		{
			return ScanDirectory(targetDirectory, false, false);
		}
		
		public FileNode ScanDirectory(string targetDirectory, bool includeParentNodes)
		{
			return ScanDirectory(targetDirectory, includeParentNodes, false);
		}

		public FileNode ScanDirectory(string targetDirectory, bool includeParentNodes, bool includeSubNodes)
		{
			if (Listener.IsVerbose)
			{
				Listener.WriteLine("Scanning for file nodes...");
				Listener.WriteLine(targetDirectory);
			}
			
			FileNode node = null;
			
			bool hasParent = Directory.Exists(Path.GetDirectoryName(targetDirectory));
						
			if (includeParentNodes)
			{
				node = GetNodeIncludingParentDirectories(targetDirectory);
			}
			else
			{
				node = GetNode(targetDirectory, includeSubNodes);
			}
			
			return node;
		}
		
		public FileNode GetNodeIncludingParentDirectories(string targetDirectory)
		{
			FileNode node = null;

			bool hasParent = false;
			do
			{
				foreach (string file in Directory.GetFiles(targetDirectory, "*.node"))
				{
					if (Listener.IsVerbose)
					{
						Listener.WriteLine("Found properties file...");
						Listener.WriteLine(file);
					}
					
					var p = Loader.LoadFromFile(file);
					
					// If the previous found properties exist
					if (node != null)
					{
						// Set the previously found properties as a sub-section of the newly found properties
						p.Nodes.Add(node.Name, node);
					}
					
					// Set the newly found properties to be the previously found properties, ready to repeat the process
					node = p;
				}
				
				hasParent = Directory.Exists(targetDirectory)
					&& targetDirectory.IndexOf(Path.DirectorySeparatorChar) != targetDirectory.LastIndexOf(Path.DirectorySeparatorChar);
				
				targetDirectory = Path.GetDirectoryName(targetDirectory);
				
				if (Listener.IsVerbose)
				{
					Listener.WriteLine("Checking directory...");
					Listener.WriteLine(targetDirectory);
				
					if (hasParent)
						Listener.WriteLine("Directory has parent. Continuing...");
					else
						Listener.WriteLine("Directory doesn't have a parent. Finished...");
				}
			}
			while (hasParent);
			
			return node;
		}
		
		public FileNode GetNode(string targetDirectory, bool includeSubNodes)
		{
			FileNode node = null;
			
			foreach (string file in Directory.GetFiles(targetDirectory, "*.node"))
			{
				if (Listener.IsVerbose)
				{
					Listener.WriteLine("Found node file...");
					Listener.WriteLine(file);
				}
				
				node = Loader.LoadFromFile(file);

				if (includeSubNodes)
					AddSubNodes(node, targetDirectory);
			}
			
			return node;
		}

		public void AddSubNodes(FileNode node, string targetDirectory)
		{
			Dictionary<string, FileNode> subNodes = new Dictionary<string, FileNode>();

			foreach (string dir in Directory.GetDirectories(targetDirectory))
			{
				foreach (string file in Directory.GetFiles(dir, "*.node"))
				{
					FileNode subNode = null;

					if (Listener.IsVerbose)
					{
						Listener.WriteLine("Found node file...");
						Listener.WriteLine(file);
					}
					
					subNode = Loader.LoadFromFile(file);

					if (!subNodes.ContainsKey(subNode.Name))
					{
						subNodes.Add(subNode.Name, subNode);
					
						AddSubNodes (subNode, dir);

					}

				}
			}

			node.Nodes = subNodes;
		}
	}
}
